﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace GMDViewer
{
	enum GMDDrawStyle
	{
		Lit = 0x01,
		Unlit = 0x02,
		Normal = 0x04,
		Tangent = 0x08,
		Textured = 0x10,
	}

	class GMDShader : IDisposable
	{
		BasicEffect m_UnlitEffect;
		Effect m_LitTexEffect;
		VertexDeclaration m_UnlitDecl, m_LitTexDecl;
		LineBatch m_lineBatch;

		public GMDShader(LineBatch linebatch)
		{
			m_lineBatch = linebatch;
		}

		public void Initialize()
		{
			m_UnlitEffect = new BasicEffect(GMDViewer.Singleton.GraphicsDevice, null);
			m_UnlitEffect.LightingEnabled = false;
			m_UnlitEffect.VertexColorEnabled = false;
			m_UnlitEffect.TextureEnabled = false;

			m_LitTexEffect = GMDViewer.Singleton.Content.Load<Effect>("ModelLitTex");

			VertexElement[] elements0 = new VertexElement[]{
				new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
			};
			m_UnlitDecl = new VertexDeclaration(GMDViewer.Singleton.GraphicsDevice, elements0);

			VertexElement[] elements1 = new VertexElement[]{
				new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
				new VertexElement(1, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0),
				new VertexElement(2, 0, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0),
			};
			m_LitTexDecl = new VertexDeclaration(GMDViewer.Singleton.GraphicsDevice, elements1);

		}

		public void DrawModelLitTextured(List<GMDModel> modellist)
		{
			GraphicsDevice device = GMDViewer.Singleton.GraphicsDevice;

			m_LitTexEffect.Parameters["World"].SetValue(Matrix.Identity);
			m_LitTexEffect.Parameters["View"].SetValue(GMDViewer.Singleton.Camera.MatView);
			m_LitTexEffect.Parameters["Projection"].SetValue(GMDViewer.Singleton.Camera.MatProj);

			m_LitTexEffect.Parameters["LightDir"].SetValue(Vector3.Normalize(new Vector3(-1, 1, -1)));
			m_LitTexEffect.Parameters["CameraPos"].SetValue(GMDViewer.Singleton.Camera.Position);
			m_LitTexEffect.Parameters["DiffuseLight"].SetValue(new Vector3(1.0f, 1.0f, 1.0f));
			m_LitTexEffect.Parameters["SpecularLight"].SetValue(new Vector3(1.0f, 1.0f, 1.0f));
			m_LitTexEffect.Parameters["AmbientLight"].SetValue(new Vector3(0.3f, 0.3f, 0.3f));
			m_LitTexEffect.Parameters["SpecularPower"].SetValue(10.0f);
			
			m_LitTexEffect.Begin();
			device.VertexDeclaration = m_LitTexDecl;

			device.RenderState.CullMode = CullMode.CullClockwiseFace;

			foreach (EffectPass pass in m_LitTexEffect.CurrentTechnique.Passes)
			{
				foreach (GMDModel model in modellist)
				{
					device.Vertices[0].SetSource(model.m_VBPosition, 0, sizeof(float) * 3);
					device.Vertices[1].SetSource(model.m_VBNormal, 0, sizeof(float) * 3);
					device.Vertices[2].SetSource(model.m_VBTexCoord, 0, sizeof(float) * 2);

					device.Indices = model.m_IB;
					pass.Begin();
					foreach (GMDModel.GMDSubSet subset in model.m_SubSets)
					{
						m_LitTexEffect.Parameters["DiffuseTexture"].SetValue(subset.m_Texture);
						device.DrawIndexedPrimitives(PrimitiveType.TriangleList,
							0, subset.iVStart, subset.iVLength, subset.iIStart, subset.iILength / 3);
					}
					pass.End();
				}
			}

			m_LitTexEffect.End();
		}

		public void DrawModelUnlit(List<GMDModel> modellist)
		{
			GraphicsDevice device = GMDViewer.Singleton.GraphicsDevice;

			m_UnlitEffect.World = Matrix.Identity;
			m_UnlitEffect.View = GMDViewer.Singleton.Camera.MatView;
			m_UnlitEffect.Projection = GMDViewer.Singleton.Camera.MatProj;
			m_UnlitEffect.Begin();
			device.VertexDeclaration = m_UnlitDecl;

			device.RenderState.CullMode = CullMode.CullClockwiseFace;

			foreach (EffectPass pass in m_UnlitEffect.CurrentTechnique.Passes)
			{
				foreach (GMDModel model in modellist)
				{
					device.Vertices[0].SetSource(model.m_VBPosition, 0, sizeof(float) * 3);
					device.Indices = model.m_IB;
					pass.Begin();
					foreach (GMDModel.GMDSubSet subset in model.m_SubSets)
					{
						device.DrawIndexedPrimitives(PrimitiveType.TriangleList,
							0, subset.iVStart, subset.iVLength, subset.iIStart, subset.iILength / 3);
					}
					pass.End();
				}
			}

			m_UnlitEffect.End();
		}


		public void DrawModelNormals(List<GMDModel> modellist)
		{
			foreach (GMDModel model in modellist)
			{
				for (int i = 0; i < model.m_PositionBuffer.Length; i++)
				{
					Vector3 vert = model.m_PositionBuffer[i];
					m_lineBatch.AddLine(vert, Color.Red, vert + model.m_NormalBuffer[i], Color.Green);
				}
			}
			m_lineBatch.Render();
		}

		public void Dispose()
		{
			if (m_UnlitEffect != null)
			{
				m_UnlitEffect.Dispose();
				m_UnlitEffect = null;
			}

			if(m_UnlitDecl != null)
			{
				m_UnlitDecl.Dispose();
				m_UnlitDecl = null;
			}

			if (m_LitTexDecl != null)
			{
				m_LitTexDecl.Dispose();
				m_LitTexDecl = null;
			}

			if (m_LitTexEffect != null)
			{
				m_LitTexEffect.Dispose();
				m_LitTexEffect = null;
			}
		}
	}
}